package myspring;

import myspring.annotation.MyAutowire;
import myspring.annotation.MyCompont;
import myspring.annotation.MyQualifier;
import myspring.annotation.MyValue;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;

public class MyAnnotationConfigApplicationContext {

    Map<String,Object> ioc=new HashMap<String, Object>();

    public MyAnnotationConfigApplicationContext(String pack){
        //定位遍历包下所有类,加载封装成BeanDefinition
        Set<BeanDefinition> beanDefinitions = this.findBeanDefinition(pack);
        //注册进IOC容器当中
        createObject(beanDefinitions);
        //自动装载
        autowireObject(beanDefinitions);
    }

    /**** 
     * @description: 自动加载对象 
     * @param: beanDefinitions 
     * @return: void 
     * @author wlq
     * @date: 2021/2/7 15:08
     */ 
    private void autowireObject(Set<BeanDefinition> beanDefinitions) {
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()) {
            BeanDefinition next = iterator.next();
            String beanName = next.getBeanName();
            Class beanClass = next.getBeanClass();
            for (Field field : beanClass.getDeclaredFields()) {
                MyAutowire annotationAutowire = field.getAnnotation(MyAutowire.class);
                if (annotationAutowire!=null){
                    MyQualifier annotationQualifier = field.getAnnotation(MyQualifier.class);
                    String value =null;
                    if (annotationQualifier!=null) {
                        //byname
                        value = annotationQualifier.value();
                    }else{
                        //bytype
                        value= field.getName();
                    }
                    Object bean= getBean(value);
                    String fieldName = field.getName();
                    String methodName="set"+ fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                    try {
                        Method method = beanClass.getMethod(methodName, field.getType());
                        Object object = getBean(next.getBeanName());
                        method.invoke(object,bean);
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public Object getBean(String beanName){
        return ioc.get(beanName);
    }

    /**** 
     * @description: 注册到Ioc容器当中，赋值 
     * @param: beanDefinitions 
     * @return: void 
     * @author wlq
     * @date: 2021/2/7 15:07
     */ 
    private void createObject(Set<BeanDefinition> beanDefinitions) {
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()) {
            BeanDefinition beanDefinition = iterator.next();
            Class clazz = beanDefinition.getBeanClass();
            String beanName = beanDefinition.getBeanName();
            try {
                //创建的对象
                Object object = clazz.getConstructor().newInstance();
                //完成属性的赋值
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    MyValue valueAnnotation = declaredField.getAnnotation(MyValue.class);
                    if(valueAnnotation!=null){
                        String value = valueAnnotation.value();
                        String fieldName = declaredField.getName();
                        String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
                        Method method = clazz.getMethod(methodName,declaredField.getType());
                        //完成数据类型转换
                        Object val = null;
                        switch (declaredField.getType().getName()){
                            case "java.lang.Integer":
                                val = Integer.parseInt(value);
                                break;
                            case "java.lang.String":
                                val = value;
                                break;
                            case "java.lang.Float":
                                val = Float.parseFloat(value);
                                break;
                        }
                        method.invoke(object, val);
                    }
                }
                //存入缓存
                ioc.put(beanName, object);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    /**** 
     * @description:  定位资源，加载到BeanDefinition中
     * @param: pack 
     * @return: java.util.Set<myspring.BeanDefinition> 
     * @author wlq
     * @date: 2021/2/7 15:05
     */ 
    private Set<BeanDefinition> findBeanDefinition(String pack){
        Set<BeanDefinition> beanDefinitions=new HashSet<BeanDefinition>();
        //获取包下所有类
        Set<Class<?>> classes = new MyTools().getClasses(pack);
        //遍历这些类，找到添加注解的类
        Iterator<Class<?>> iterator = classes.iterator();
        while (iterator.hasNext()) {
            Class<?> clazz = iterator.next();
            MyCompont myCompont = clazz.getAnnotation(MyCompont.class);
            if (myCompont!=null) {
                String beanname = myCompont.value();
                if ("".equals(beanname)){
                    //将首字母转小写，获取
                    String classname=clazz.getName().replaceAll(clazz.getPackage().getName()+".","");
                    beanname=classname.substring(0,1).toLowerCase()+classname.substring(1);
                }
                //将这些类封装beandefinition
                BeanDefinition beanDefinition = new BeanDefinition(beanname, clazz);
                beanDefinitions.add(beanDefinition);
            }
        }
        return beanDefinitions;
    }

}
